///////////////////////////////////////////////////////////////////////////
// CLinkDateEdit message handlers


#include "StdAfx.h"
#include "LinkDate.h"
#include "LinkInputNode.h"
#include "CommonFun.h"
#include "../Res/resource.h"

CLinkDateEdit::CLinkDateEdit(INPUT_FIELD_INFO* pFieldInfo):CLinkCtrl(pFieldInfo)
{
    m_strMask = _T("YYYY-MM-DD");
	CLinkInputNode::AddInput(this, CtrlType);
	
	if(pFieldInfo)
	{
		pFieldInfo->pLinkCtrl = this;
		pFieldInfo->dwCtrlType = CtrlType;
	}
}

CLinkDateEdit::~CLinkDateEdit()
{
	CLinkInputNode::DelInput(this);
}

CString	CLinkDateEdit::GetControlData(BOOL bTrimBlank, BOOL bReplaceSingleQuotation)
{
	CString strValue;
	GetWindowText(strValue);
	
	if(bTrimBlank)
	{
		strValue.TrimLeft();
		strValue.TrimRight();
	}
	
	if(bReplaceSingleQuotation)
		strValue.Replace(_T("'"), _T("''"));
	
	return strValue;
}

BOOL CLinkDateEdit::CheckCtrlDataValid()
{
	if(!IsDateTimeValid())
	{
		GYMsgBox(IDS_PAT_INVALID_DATE, MB_OK|MB_ICONINFORMATION);
		return FALSE;
	}
	
	return TRUE;
}

BOOL CLinkDateEdit::IsInRange(CString strNum, int nMin, int nMax)
{
	int nNum = _ttoi(strNum);
	return (nNum >= nMin && nNum <= nMax);
}

BOOL CLinkDateEdit::IsLeapYear(int nYear)
{
	if((nYear % 400) == 0)
		return TRUE;
	else if((nYear % 100) == 0)
		return FALSE;
	else if((nYear % 4) == 0)
		return TRUE;
	else
		return FALSE;
}

BOOL CLinkDateEdit::IsDateTimeValid()
{
	BOOL bValid = TRUE;
	CString strMask = GetMask();
	CString strDate;
	GetWindowText(strDate);

	int nYear = 2012;
	int nMonth = 1;
	int nPos = strMask.Find(_T("YYYY"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 4);
		bValid = IsInRange(strDatePart, 1900, 2050);

		nYear = _ttoi(strDatePart);
	}
	
	nPos = strMask.Find(_T("MM"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 2);
		bValid = IsInRange(strDatePart, 1, 12);

		nMonth = _ttoi(strDatePart);
	}
	
	nPos = strMask.Find(_T("DD"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 2);
		switch(nMonth)
		{
		case 1:case 3:case 5:case 7:case 8:case 10:case 12:
			bValid = IsInRange(strDatePart, 1, 31);
			break;
		case 4:case 6:case 9:case 11:
			bValid = IsInRange(strDatePart, 1, 30);
			break;
		case 2:
			{
				if(IsLeapYear(nYear))
					bValid = IsInRange(strDatePart, 1, 29);
				else
					bValid = IsInRange(strDatePart, 1, 28);
			}
			break;
		}
	}
	
	nPos = strMask.Find(_T("hh"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 2);
		bValid = IsInRange(strDatePart, 0, 23);
	}
	
	nPos = strMask.Find(_T("mm"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 2);
		bValid = IsInRange(strDatePart, 0, 59);
	}
	
	nPos = strMask.Find(_T("ss"));
	if(bValid && nPos >= 0)
	{
		CString strDatePart = strDate.Mid(nPos, 2);
		bValid = IsInRange(strDatePart, 0, 59);
	}

	return bValid;
}


BOOL CLinkDateEdit::OnCtrlKeyDown(UINT nChar)
{
	TCHAR c;

	CString old;
	GetWindowText(old);

	int nPos = 0;
	int nStartPos = 0;
	int nEndPos = 0;
	GetSel(nStartPos, nEndPos);
    switch (nChar)
	{
		case VK_SHIFT:case VK_LEFT:case VK_RIGHT:case VK_INSERT:
			{
				//  No process
				return FALSE;
			}
		case VK_UP:
			{
				nEndPos--;
				nPos = nEndPos;
			}
			break;
		case VK_DOWN:
			{
				nEndPos++;
				nPos = nEndPos;
			}
			break;
		case VK_BACK:
			{
				if(nEndPos <= 0)
					return FALSE;

				//  change the char to '0'
				if(nStartPos != nEndPos)
				{
					CString str = old;
					for(int i = nStartPos; i < nEndPos; i++)
					{
						if( (c = m_strMask[i]) == 'D' || c == 'M' || c == 'Y' || c == 'h' || c == 'm' || c == 's')
						{
							str.SetAt(i, (TCHAR)'0');
						}
					}
					SetWindowText(str);

					nPos = nStartPos;	
				}
				else
				{
					nEndPos--;
					
					if(	nEndPos <= old.GetLength() && nEndPos <= m_strMask.GetLength() && 
						((c = m_strMask[nEndPos]) == 'D' || c == 'M' || c == 'Y' || c == 'h' || c == 'm' || c == 's'))
					{
						CString str = old;
						str.SetAt(nEndPos, (TCHAR)'0');
						SetWindowText(str);
					}

					nPos = nEndPos;	
				}

			}
			break;
		case VK_DELETE:
			{
				if(nStartPos >= m_strMask.GetLength())
					return FALSE;
				
				//  change the char to '0'
				if(nStartPos != nEndPos)
				{
					CString str = old;
					for(int i = nStartPos; i < nEndPos; i++)
					{
						if( (c = m_strMask[i]) == 'D' || c == 'M' || c == 'Y' || c == 'h' || c == 'm' || c == 's')
							str.SetAt(i, (TCHAR)'0');
					}
					SetWindowText(str);
				}
				else
				{
					if(	nStartPos <= old.GetLength() && nStartPos <= m_strMask.GetLength() && 
					((c = m_strMask[nStartPos]) == 'D' || c == 'M' || c == 'Y' || c == 'h' || c == 'm' || c == 's'))
					{
						CString str = old;
						str.SetAt(nStartPos, (TCHAR)'0');
						SetWindowText(str);
					}
				}

				nPos = nStartPos;	
			}
			break;
		case VK_NUMPAD0:case VK_NUMPAD1:case VK_NUMPAD2:case VK_NUMPAD3:
		case VK_NUMPAD4:case VK_NUMPAD5:case VK_NUMPAD6:case VK_NUMPAD7:
		case VK_NUMPAD8:case VK_NUMPAD9:
			{
				nChar = nChar - VK_NUMPAD0 + '0';
			}
        case '0':case '1':case '2':case '3':
        case '4':case '5':case '6':case '7':
        case '8':case '9':
			{
				if(	nStartPos < old.GetLength() && nStartPos < m_strMask.GetLength() && (UINT)old[nStartPos] != nChar &&
					((c = m_strMask[nStartPos]) == 'D' || c == 'M' || c == 'Y' || c == 'h' || c == 'm' || c == 's'))
				{
					CString str = old;
					str.SetAt(nStartPos, (TCHAR)nChar);
					SetWindowText(str);
				}
				if (++nStartPos < m_strMask.GetLength())
				{
					for ( c = m_strMask[nStartPos]; nStartPos < m_strMask.GetLength() && c != 'D' && c != 'M' && c != 'Y' && c != 'h' && c != 'm' && c != 's'; c = m_strMask[nStartPos])
						nStartPos++;
				}
				nPos = nStartPos;
			}
            break;
        default:
			{
				if (++nEndPos < m_strMask.GetLength())
				{
					for( c = m_strMask[nEndPos]; nEndPos < m_strMask.GetLength() && c != 'D' && c != 'M' && c != 'Y' && c != 'h' && c != 'm' && c != 's'; c = m_strMask[nEndPos])
						nEndPos++;
				}
				nPos = nEndPos;	
			}
            break;
    }

    SetSel(nPos, nPos);
	return TRUE;
}

BOOL CLinkDateEdit::PreTranslateMessage(MSG* pMsg)
{
	return CLinkCtrl::PreTranslateMessage(pMsg, this);
}

void CLinkDateEdit::PreSubclassWindow() 
{
	CTime curTime = CTime::GetCurrentTime();
    SetDateTime(curTime);
	
	CLinkCtrl::PreSubclassWindow(this);
	CEdit::PreSubclassWindow();
}

void CLinkDateEdit::SetDateTime(CTime dt)
{
    CString str;
    int i, n = m_strMask.GetLength();
    for (i = 0; i < n; i++)
	{
        CString s;
        int val;
        TCHAR c = m_strMask[i];
        switch (c)
		{
            case 'D':case 'M':case 'Y':case 'h':case 'm':case 's':
                for(; i < n; i++)
				{
                    if (m_strMask[i] == c)
					{
						s += c;
					}
                    else
					{
						i--;
						break;
					}
                }
                break;

            default :
                break;
        }
        CString format;
        format.Format(_T("%%0%dd"), s.GetLength());
        switch (c)
		{
            case 'D':
                val = dt.GetDay();
                ::VSetInRange(val, 0, 31);
                s.Format(format, val);
                break;
            case 'M':
                val = dt.GetMonth();
                ::VSetInRange(val, 1, 12);
                s.Format(format, val);
                break;
            case 'Y':
                val = dt.GetYear();
                ::VSetInRange(val, 1900, 9990);
                s.Format(format, val);
                break;
            case 'h':
                val = dt.GetHour();
                ::VSetInRange(val, 0, 23);
                s.Format(format, val);
                break;
            case 'm':
                val = dt.GetMinute();
                ::VSetInRange(val, 0, 59);
                s.Format(format, val);
                break;
            case 's':
                val = dt.GetSecond();
                ::VSetInRange(val, 0, 59);
                s.Format(format, val);
                break;
            default :
                s = c;
                break;
        }
        str += s;
    }
    int pos;
    GetSel(pos, pos);
    SetWindowText(str);
    SetSel(pos, pos);
}


BOOL CLinkDateEdit::CopyFrom(CLinkDateEdit* pFrom)
{
	if(!pFrom)
		return FALSE;
	
	CString strValue = pFrom->GetControlData(TRUE, FALSE);
	SetWindowText(strValue);
	
	return TRUE;
}

BOOL CLinkDateEdit::SetToday()
{
	CTime curTime = CTime::GetCurrentTime();
    SetDateTime(curTime);
	
	return TRUE;
}
